﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.IO;
using System.Diagnostics;
using System.Threading;


namespace WpfApplication1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        bool closing = false;
        const int skeletonCount = 6;
        Skeleton[] allSkeletons = new Skeleton[skeletonCount];
        KinectSensor _sensor;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (KinectSensor.KinectSensors.Count > 0)
            {
                _sensor = KinectSensor.KinectSensors[0];
                if (_sensor.Status == KinectStatus.Connected)
                {
                    _sensor.ColorStream.Enable();
                    _sensor.DepthStream.Enable();
                    _sensor.SkeletonStream.Enable();
                    //_sensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(_sensor_AllFramesReady);
                    //_sensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
                    //_sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                    _sensor.Start();
                }
            }
        }

        //void _sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)
        //{
        //    using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
        //    {
        //        if (colorFrame == null)
        //        {
        //            return;
        //        }
        //        byte[] pixels = new byte[colorFrame.PixelDataLength];
        //        colorFrame.CopyPixelDataTo(pixels);
        //        int stride = colorFrame.Width * 4;
        //        //image1.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null, pixels, stride);
        //    }
        //    //using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
        //    //{
        //    //    if (depthFrame == null)
        //    //    {
        //    //        return;
        //    //    }
        //    //    byte[] pixels = GenerateColoredBytes(depthFrame);
        //    //    //depthFrame.CopyPixelDataTo(pixels);
        //    //    int stride = depthFrame.Width * 4;
        //    //    image1.Source = BitmapSource.Create(depthFrame.Width, depthFrame.Height, 96, 96, PixelFormats.Bgr32, null, pixels, stride);
        //    //}
        //    if (closing)
        //    {
        //        return;
        //    }
        //    Skeleton first = GetFirstSkeleton(e);
        //    if (first == null)
        //    {
        //        return;
        //    }
        //    GetCameraPoint(first, e);
        //}

        private void GetCameraPoint(Skeleton first, AllFramesReadyEventArgs e)
        {
            using (DepthImageFrame depth = e.OpenDepthImageFrame())
            {
                if (depth == null)
                {
                    return;
                }
                DepthImagePoint headDepthPoint =
                    depth.MapFromSkeletonPoint(first.Joints[JointType.Head].Position);
                DepthImagePoint leftDepthPoint =
                    depth.MapFromSkeletonPoint(first.Joints[JointType.HandLeft].Position);
                DepthImagePoint rightDepthPoint =
                    depth.MapFromSkeletonPoint(first.Joints[JointType.HandRight].Position);

                ColorImagePoint headColorPoint =
                    depth.MapToColorImagePoint(headDepthPoint.X, headDepthPoint.Y,
                    ColorImageFormat.RgbResolution640x480Fps30);
                ColorImagePoint leftColorPoint =
                  depth.MapToColorImagePoint(leftDepthPoint.X, leftDepthPoint.Y,
                  ColorImageFormat.RgbResolution640x480Fps30);
                ColorImagePoint rightColorPoint =
                  depth.MapToColorImagePoint(rightDepthPoint.X, rightDepthPoint.Y,
                    ColorImageFormat.RgbResolution640x480Fps30);

                //CameraPosition(headEllipse, headColorPoint);
                //CameraPosition(leftEllipse, leftColorPoint);
                //CameraPosition(rightEllipse, rightColorPoint);
            }
        }

        private void CameraPosition(FrameworkElement element, ColorImagePoint point)
        {
            Canvas.SetLeft(element, point.X - element.Width / 2);
            Canvas.SetTop(element, point.Y - element.Height / 2);
        }

        private Skeleton GetFirstSkeleton(AllFramesReadyEventArgs e)
        {
            using (SkeletonFrame skeletonFrameData = e.OpenSkeletonFrame())
            {
                if (skeletonFrameData == null)
                {
                    return null;
                }
                skeletonFrameData.CopySkeletonDataTo(allSkeletons);
                Skeleton first = (from s in allSkeletons
                                  where s.TrackingState == SkeletonTrackingState.Tracked
                                  select s).FirstOrDefault();
                return first;
            }
        }

        //private byte[] GenerateColoredBytes(DepthImageFrame depthFrame)
        //{
        //    short[] rawDepthData = new short[depthFrame.PixelDataLength];
        //    depthFrame.CopyPixelDataTo(rawDepthData);
        //    //height x width x 4   (Red , Green , Blue , empty byte)
        //    Byte[] pixels = new Byte[depthFrame.Height * depthFrame.Width * 4];

        //    const int BlueIndex = 0;
        //    const int GreenIndex = 1;
        //    const int RedIndex = 2;

        //    for (int depthIndex = 0, colorIndex = 0;
        //        depthIndex < rawDepthData.Length && colorIndex < pixels.Length;
        //        depthIndex++, colorIndex += 4)
        //    {
        //        int player = rawDepthData[depthIndex] & DepthImageFrame.PlayerIndexBitmask;
        //        int depth = rawDepthData[depthIndex] << DepthImageFrame.PlayerIndexBitmaskWidth;
        //        if (depth <= 900)
        //        {
        //            pixels[colorIndex + BlueIndex] = 255;
        //            pixels[colorIndex + GreenIndex] = 0;
        //            pixels[colorIndex + RedIndex] = 0;
        //        }
        //        else if (depth > 900 && depth < 2000)
        //        {
        //            pixels[colorIndex + BlueIndex] = 0;
        //            pixels[colorIndex + GreenIndex] = 255;
        //            pixels[colorIndex + RedIndex] = 255;
        //        }
        //        else if (depth > 2000)
        //        {
        //            pixels[colorIndex + BlueIndex] = 0;
        //            pixels[colorIndex + GreenIndex] = 0;
        //            pixels[colorIndex + RedIndex] = 255;
        //        }
        //        //byte intensity = CaculateIntensityFromDepth(depth);
        //        //pixels[colorIndex + BlueIndex] = intensity;
        //        //pixels[colorIndex + GreenIndex] = intensity;
        //        //pixels[colorIndex + RedIndex] = intensity;

        //        //if (player > 0)
        //        //{
        //        //    pixels[colorIndex + BlueIndex] = Colors.Gold.B;
        //        //    pixels[colorIndex + GreenIndex] = Colors.Gold.G;
        //        //    pixels[colorIndex + RedIndex] = Colors.Gold.R;
        //        //}
        //    }
        //    return pixels;

        //}
        //const float MaxDepthDistance = 4000; // max value returned

        //const float MinDepthDistance = 850; // min value returned

        //const float MaxDepthDistanceOffset = MaxDepthDistance - MinDepthDistance;
        //private byte CaculateIntensityFromDepth(int distance)
        //{
        //    return (byte)(255 - (255 * Math.Max(distance - MinDepthDistance, 0) / MaxDepthDistanceOffset));
        //}


        void StopKinect(KinectSensor sensor)
        {
            if (sensor.IsRunning)
            {
                sensor.Stop();
                sensor.AudioSource.Stop();
            }
        }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            StopKinect(_sensor);
        }

        double _amountOfTimeToRecord;
        string _lastRecordFileName;
        private event RoutedEventHandler FinishedRecording;

        private void RecordAudio(KinectSensor kinectSensor)
        {
            if (kinectSensor == null)
            {
                return;
            }
            int recordingLength = (int)_amountOfTimeToRecord * 2 * 16000;
            byte[] buffer = new byte[1024];
            using (FileStream _fileStream = new FileStream(_lastRecordFileName, FileMode.Create))
            {
                WriteWavHeader(_fileStream,recordingLength);
                using (Stream audioStream = kinectSensor.AudioSource.Start())
                {
                    int count, totalCount = 0;
                    while ((count = audioStream.Read(buffer, 0, buffer.Length)) > 0 && totalCount < recordingLength)
                    {
                        _fileStream.Write(buffer, 0, count);
                        totalCount += count;
                    }
                }
            }
            if (FinishedRecording!=null)
            {
                FinishedRecording(null, null);
            }
        }

        private static void WriteWavHeader(FileStream stream, int dataLength)
        {
            using (MemoryStream memStream = new MemoryStream(64))
            {
                int cbFormat = 18; //sizeof(WAVEFORMATEX)
                WAVEFORMATEX format = new WAVEFORMATEX()
                {
                    wFormatTag = 1,
                    nChannels = 1,
                    nSamplesPerSec = 16000,
                    nAvgBytesPerSec = 32000,
                    nBlockAlign = 2,
                    wBitsPerSample = 16,
                    cbSize = 0
                };

                using (var bw = new BinaryWriter(memStream))
                {
                    //RIFF header
                    WriteString(memStream, "RIFF");
                    bw.Write(dataLength + cbFormat + 4); //File size - 8
                    WriteString(memStream, "WAVE");
                    WriteString(memStream, "fmt ");
                    bw.Write(cbFormat);

                    //WAVEFORMATEX
                    bw.Write(format.wFormatTag);
                    bw.Write(format.nChannels);
                    bw.Write(format.nSamplesPerSec);
                    bw.Write(format.nAvgBytesPerSec);
                    bw.Write(format.nBlockAlign);
                    bw.Write(format.wBitsPerSample);
                    bw.Write(format.cbSize);

                    //data header
                    WriteString(memStream, "data");
                    bw.Write(dataLength);
                    memStream.WriteTo(stream);
                }
            }
        }

        private static void WriteString(Stream stream, string s)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(s);
            Debug.Assert(bytes.Length == s.Length);
            stream.Write(bytes, 0, bytes.Length);
        }
        struct WAVEFORMATEX
        {
            public ushort wFormatTag;
            public ushort nChannels;
            public uint nSamplesPerSec;
            public uint nAvgBytesPerSec;
            public ushort nBlockAlign;
            public ushort wBitsPerSample;
            public ushort cbSize;
        }

        void audiosample_FinishedRecording(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke(new ThreadStart(ReenableButtons));
        }
        private void ReenableButtons()
        {
            RecordButton.IsEnabled = true;
            PlayButton.IsEnabled = true;
        }


        private void RecordButton_Click(object sender, RoutedEventArgs e)
        {
            RecordButton.IsEnabled = false;
            PlayButton.IsEnabled = false;
            _amountOfTimeToRecord = RecordForTimeSpan.Value;
            _lastRecordFileName = DateTime.Now.ToString("yyyyMMddHHmmss") + "_wav.wav";
            var t = new Thread(new ParameterizedThreadStart((RecordAudio)));
           // t.Start(Kinect);
           // t.SetApartmentState(ApartmentState.MTA);
            t.Start(_sensor);
        //    RecordAudio(_sensor);
        }

        private void RecordAudio(object kinectSensor)
        {
            KinectSensor _kinectSensor = (KinectSensor)kinectSensor;
            RecordAudio(_kinectSensor);
        }

        private void PlayButton_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(_lastRecordFileName) && File.Exists(_lastRecordFileName))
            {
                audioPlayer.Source = new Uri(_lastRecordFileName, UriKind.RelativeOrAbsolute);
                audioPlayer.LoadedBehavior = MediaState.Play;
                audioPlayer.UnloadedBehavior = MediaState.Close;
            }
        }




    }
}
